package com.example.smartwaterapi.controller;

import com.example.smartwaterapi.common.api.RestApiResponse;
import com.example.smartwaterapi.utils.TosClientUtils;
import com.example.smartwaterapi.service.DeviceService;
import com.volcengine.tos.model.object.GetObjectV2Output;
import com.volcengine.tos.model.object.PutObjectOutput;
import com.volcengine.tos.comm.common.ACLType;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import jakarta.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * 文件管理控制器
 */
@Tag(name = "文件管理", description = "文件上传和下载接口")
@RestController
@RequestMapping("/api/files")
@RequiredArgsConstructor
@Slf4j
public class FileController {

    private final TosClientUtils tosClientUtils;
    private final DeviceService deviceService;

    /**
     * 上传文件
     */
    @Operation(summary = "上传文件", description = "支持上传图片等文件到对象存储，对象继承桶的公开权限")
    @PostMapping("/upload")
    public RestApiResponse<Map<String, Object>> uploadFile(
            @Parameter(description = "文件", required = true)
            @RequestParam("file") MultipartFile file,
            @Parameter(description = "用户ID", required = true)
            @RequestParam("userId") String userId,
            @Parameter(description = "设备ID（可选，用于表盘背景）", required = false)
            @RequestParam(value = "deviceId", required = false) String deviceId,
            @Parameter(description = "设备序列号（可选，用于表盘背景）", required = false)
            @RequestParam(value = "deviceSn", required = false) String deviceSn,
            @Parameter(description = "文件类型", required = false)
            @RequestParam(value = "fileType", required = false) String fileType,
            @Parameter(description = "文件分类", required = false)
            @RequestParam(value = "category", required = false) String category,
            @Parameter(description = "原始文件名", required = false)
            @RequestParam(value = "originalFileName", required = false) String originalFileName,
            HttpServletRequest request) {
        
        try {
            log.info("📤 开始处理文件上传请求: userId={}, deviceId={}, fileType={}, category={}", 
                     userId, deviceId, fileType, category);
            
            // 验证文件
            if (file.isEmpty()) {
                return RestApiResponse.badRequest("文件不能为空");
            }

            // 验证用户ID
            if (userId == null || userId.trim().isEmpty()) {
                return RestApiResponse.badRequest("用户ID不能为空");
            }

            // 验证文件类型
            String contentType = file.getContentType();
            if (contentType == null || !isValidImageType(contentType)) {
                return RestApiResponse.badRequest("只支持上传图片文件（jpg, jpeg, png, gif）");
            }

            // 验证文件大小（20MB）
            if (file.getSize() > 20 * 1024 * 1024) {
                return RestApiResponse.badRequest("文件大小不能超过20MB");
            }

            // 确定文件名
            String finalFileName;
            String originalFilename = file.getOriginalFilename();
            if (originalFileName != null && !originalFileName.trim().isEmpty()) {
                finalFileName = originalFileName;
            } else {
                finalFileName = originalFilename;
            }
            
            String fileExtension = "";
            if (finalFileName != null && finalFileName.contains(".")) {
                fileExtension = finalFileName.substring(finalFileName.lastIndexOf("."));
            }
            
            String fileName = UUID.randomUUID().toString() + fileExtension;
            String datePath = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));
            
            // 根据文件类型选择路径
            String basePath;
            if ("dial_background_png".equals(fileType) || "dial_background".equals(category)) {
                basePath = "dial-background";
            } else {
                basePath = "uploads";
            }
            String objectKey = basePath + "/" + datePath + "/" + fileName;

            // 上传到TOS（对象继承桶权限，无需单独设置ACL）
            PutObjectOutput result = tosClientUtils.uploadStream(
                objectKey, 
                file.getInputStream(), 
                file.getSize()
            );
 
            // 获取TOS直接访问URL
            String directAccessUrl = tosClientUtils.getObjectUrl(objectKey);
            
            // 构建后端代理访问URL（备选方式）
            String scheme = request.getScheme();
            String serverName = request.getServerName();
            int serverPort = request.getServerPort();
            String contextPath = request.getContextPath();
            
            StringBuilder baseUrl = new StringBuilder();
            baseUrl.append("https").append("://").append(serverName);
            if ((scheme.equals("http") && serverPort != 80) || 
                (scheme.equals("https") && serverPort != 443)) {
                baseUrl.append(":").append(serverPort);
            }
            baseUrl.append(contextPath);
            
            String proxyAccessUrl = baseUrl.toString() + "/api/files/view/" + objectKey;

            // 检查是否为表盘背景图片
            boolean isDialBackground = "dial_background_png".equals(fileType) || 
                                     "dial_background".equals(category) ||
                                     (deviceSn != null && finalFileName != null && finalFileName.toUpperCase().contains("BGP"));
            
            boolean dialBackgroundUpdated = false;
            
            if (isDialBackground) {
                try {
                    log.info("🎨 检测到表盘背景图片上传: userId={}, deviceId={}, deviceSn={}, fileType={}", 
                             userId, deviceId, deviceSn, fileType);
                    
                    // 使用智能更新策略，使用proxyUrl作为表盘背景URL
                    dialBackgroundUpdated = deviceService.smartUpdateDialBackground(
                        userId, deviceId, deviceSn, proxyAccessUrl
                    );
                    
                    if (dialBackgroundUpdated) {
                        log.info("✅ 表盘背景URL更新成功: URL={}", proxyAccessUrl);
                    } else {
                        log.warn("⚠️ 表盘背景URL更新失败，请检查设备绑定状态");
                    }
                    
                } catch (Exception e) {
                    log.error("❌ 更新设备表盘背景URL异常: deviceId={}, deviceSn={}, userId={}", 
                             deviceId, deviceSn, userId, e);
                }
            }

            // 构建响应数据
            Map<String, Object> responseData = new HashMap<>();
            responseData.put("fileName", fileName);
            responseData.put("originalName", finalFileName);
            responseData.put("objectKey", objectKey);
            responseData.put("fileSize", file.getSize());
            responseData.put("contentType", contentType);
            responseData.put("uploadTime", LocalDateTime.now());
            // 返回直接访问URL（推荐使用）
            responseData.put("accessUrl", directAccessUrl);
            responseData.put("directUrl", directAccessUrl);
            // 返回代理访问URL（备选方案）
            responseData.put("proxyUrl", proxyAccessUrl);
            
            // 添加上传参数信息
            if (userId != null) responseData.put("userId", userId);
            if (deviceId != null) responseData.put("deviceId", deviceId);
            if (deviceSn != null) responseData.put("deviceSn", deviceSn);
            if (fileType != null) responseData.put("fileType", fileType);
            if (category != null) responseData.put("category", category);
            
            // 添加表盘背景特定信息
            responseData.put("isDialBackground", isDialBackground);
            responseData.put("dialBackgroundUpdated", dialBackgroundUpdated);
            // 添加权限信息
            responseData.put("isPublic", true);
            responseData.put("permission", "继承桶权限(public-read)");
            // 添加用户和设备信息
            responseData.put("userId", userId);
            responseData.put("fileType", fileType);
            responseData.put("category", category);
            
            // 添加表盘背景相关信息
            if (isDialBackground) {
                responseData.put("isDialBackground", true);
                responseData.put("deviceId", deviceId);
                responseData.put("deviceSn", deviceSn);
                responseData.put("dialBackgroundUrlUpdated", true);
            }

            log.info("文件上传成功: {} -> {} (继承桶权限)", objectKey, directAccessUrl);
            return RestApiResponse.created(responseData);

        } catch (Exception e) {
            log.error("文件上传失败", e);
            return RestApiResponse.error("文件上传失败: " + e.getMessage());
        }
    }

    
    /**
     * 查看文件（最简版本 - 直接使用HttpServletResponse）
     */
    @GetMapping("/view/**")
    public void viewFileSimple(HttpServletRequest request, jakarta.servlet.http.HttpServletResponse response) {
        try {
            String requestURI = request.getRequestURI();
            String viewPrefix = "/api/files/view/";
            int prefixIndex = requestURI.indexOf(viewPrefix);
            
            if (prefixIndex == -1) {
                response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
                return;
            }
            
            String objectKey = requestURI.substring(prefixIndex + viewPrefix.length());
            objectKey = java.net.URLDecoder.decode(objectKey, "UTF-8");
            
            log.info("请求文件: {}", objectKey);
            
            // 检查文件是否存在
            if (!tosClientUtils.objectExists(objectKey)) {
                response.setStatus(HttpServletResponse.SC_NOT_FOUND);
                return;
            }
            
            // 下载文件
            GetObjectV2Output result = tosClientUtils.downloadObject(objectKey);
            if (result == null || result.getContent() == null) {
                response.setStatus(HttpServletResponse.SC_NOT_FOUND);
                return;
            }
            
            // 设置响应头
            response.setContentType("image/png");
            response.setContentLengthLong(result.getContentLength());
            response.setHeader("Content-Disposition", "inline");
            response.setHeader("Cache-Control", "max-age=3600");
            
            // 直接流式传输
            try (InputStream inputStream = result.getContent()) {
                byte[] buffer = new byte[8192];
                int bytesRead;
                while ((bytesRead = inputStream.read(buffer)) != -1) {
                    response.getOutputStream().write(buffer, 0, bytesRead);
                }
                response.getOutputStream().flush();
            }
            
            log.info("文件传输完成: {}", objectKey);
            
        } catch (Exception e) {
            log.error("文件访问异常", e);
            try {
                response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            } catch (Exception ex) {
                log.error("设置错误状态失败", ex);
            }
        }
    }

    /**
     * 删除文件
     */
    /**
     * 删除文件
     */
    @Operation(summary = "删除文件", description = "删除指定的文件")
    @DeleteMapping("/delete/{objectKey:.+}")
    public RestApiResponse<Void> deleteFile(
            @Parameter(description = "文件对象键", required = true)
            @PathVariable String objectKey) {

        try {
            // URL解码
            try {
                objectKey = java.net.URLDecoder.decode(objectKey, "UTF-8");
            } catch (Exception e) {
                log.warn("URL解码失败，使用原始路径: {}", objectKey);
            }

            tosClientUtils.deleteObject(objectKey);
            log.info("文件删除成功: {}", objectKey);
            return RestApiResponse.ok();
        } catch (Exception e) {
            log.error("文件删除失败", e);
            return RestApiResponse.error("文件删除失败: " + e.getMessage());
        }
    }

    /**
     * 获取文件信息
     */
    @Operation(summary = "获取文件信息", description = "获取文件的基本信息和访问URL")
    @GetMapping("/info/{objectKey:.+}")
    public RestApiResponse<Map<String, Object>> getFileInfo(
            @Parameter(description = "文件对象键", required = true)
            @PathVariable String objectKey) {

        try {
            // URL解码
            try {
                objectKey = java.net.URLDecoder.decode(objectKey, "UTF-8");
            } catch (Exception e) {
                log.warn("URL解码失败，使用原始路径: {}", objectKey);
            }

            // 检查文件是否存在
            if (!tosClientUtils.objectExists(objectKey)) {
                return RestApiResponse.notFound("文件不存在");
            }

            // 获取文件权限
            ACLType acl = tosClientUtils.getObjectACL(objectKey);

            // 构建响应数据
            Map<String, Object> responseData = new HashMap<>();
            responseData.put("objectKey", objectKey);
            responseData.put("accessUrl", tosClientUtils.getObjectUrl(objectKey));
            responseData.put("permission", acl.toString());
            responseData.put("isPublic", acl.toString().contains("PUBLIC"));
            responseData.put("fileName", objectKey.substring(objectKey.lastIndexOf("/") + 1));
            responseData.put("bucketPermission", tosClientUtils.getBucketACL().toString());

            return RestApiResponse.ok(responseData);
        } catch (Exception e) {
            log.error("获取文件信息失败", e);
            return RestApiResponse.error("获取文件信息失败: " + e.getMessage());
        }
    }

    /**
     * 修复文件权限
     */
    @Operation(summary = "修复文件权限", description = "将文件设置为公开可读权限")
    @PostMapping("/fix-permission/{objectKey:.+}")
    public RestApiResponse<Void> fixFilePermission(
            @Parameter(description = "文件对象键", required = true)
            @PathVariable String objectKey) {

        try {
            // URL解码
            try {
                objectKey = java.net.URLDecoder.decode(objectKey, "UTF-8");
            } catch (Exception e) {
                log.warn("URL解码失败，使用原始路径: {}", objectKey);
            }

            // 检查文件是否存在
            if (!tosClientUtils.objectExists(objectKey)) {
                return RestApiResponse.notFound("文件不存在");
            }

            // 设置文件为公开可读
            tosClientUtils.setObjectACL(objectKey, ACLType.ACL_PUBLIC_READ);

            log.info("文件权限修复成功: {}", objectKey);
            return RestApiResponse.ok();
        } catch (Exception e) {
            log.error("修复文件权限失败", e);
            return RestApiResponse.error("修复文件权限失败: " + e.getMessage());
        }
    }

    /**
     * 获取桶权限信息
     */
    @Operation(summary = "获取桶权限", description = "获取存储桶的权限信息")
    @GetMapping("/bucket/acl")
    public RestApiResponse<Map<String, Object>> getBucketACL() {
        try {
            ACLType acl = tosClientUtils.getBucketACL();
            
            Map<String, Object> responseData = new HashMap<>();
            responseData.put("bucketName", tosClientUtils.getBucketName());
            responseData.put("permission", acl.toString());
            responseData.put("isPublic", acl.toString().contains("PUBLIC"));
            
            return RestApiResponse.ok(responseData);
        } catch (Exception e) {
            log.error("获取桶权限失败", e);
            return RestApiResponse.error("获取桶权限失败: " + e.getMessage());
        }
    }

    /**
     * 设置桶权限
     */
    @Operation(summary = "设置桶权限", description = "设置存储桶的权限")
    @PostMapping("/bucket/acl")
    public RestApiResponse<Void> setBucketACL(
            @Parameter(description = "权限类型", required = true)
            @RequestParam String permission) {
        
        try {
            if ("public".equals(permission)) {
                tosClientUtils.setBucketACL(ACLType.ACL_PUBLIC_READ);
            } else if ("private".equals(permission)) {
                tosClientUtils.setBucketACL(ACLType.ACL_PRIVATE);
            } else {
                return RestApiResponse.badRequest("无效的权限类型，支持：public, private");
            }
            
            log.info("桶权限设置成功: {}", permission);
            return RestApiResponse.ok();
        } catch (Exception e) {
            log.error("设置桶权限失败", e);
            return RestApiResponse.error("设置桶权限失败: " + e.getMessage());
        }
    }

    /**
     * 测试TOS连接
     */
    @Operation(summary = "测试TOS连接", description = "测试TOS连接是否正常")
    @GetMapping("/test-tos")
    public RestApiResponse<Map<String, Object>> testTos() {
        try {
            // 创建一个测试文件
            String testKey = "test/test-connection.txt";
            String testContent = "TOS连接测试 - " + LocalDateTime.now();
            
            // 上传测试文件
            tosClientUtils.uploadString(testKey, testContent);
            log.info("测试文件上传成功: {}", testKey);
            
            // 下载测试文件
            GetObjectV2Output result = tosClientUtils.downloadObject(testKey);
            byte[] downloadedContent;
            try (InputStream inputStream = result.getContent()) {
                downloadedContent = inputStream.readAllBytes();
            }
            String downloadedString = new String(downloadedContent);
            log.info("测试文件下载成功: {}", testKey);
            
            // 删除测试文件
            tosClientUtils.deleteObject(testKey);
            log.info("测试文件删除成功: {}", testKey);
            
            Map<String, Object> testResult = new HashMap<>();
            testResult.put("status", "success");
            testResult.put("message", "TOS连接正常");
            testResult.put("uploadedContent", testContent);
            testResult.put("downloadedContent", downloadedString);
            testResult.put("testTime", LocalDateTime.now());
            testResult.put("bucketName", tosClientUtils.getBucketName());
            
            return RestApiResponse.ok(testResult);
            
        } catch (Exception e) {
            log.error("TOS连接测试失败", e);
            return RestApiResponse.error("TOS连接测试失败: " + e.getMessage());
        }
    }

    /**
     * 上传表盘背景图片
     */
    @Operation(summary = "上传表盘背景图片", description = "上传表盘背景图片，并更新设备的dial_background_url字段")
    @PostMapping("/dial-background")
    public RestApiResponse<Map<String, Object>> uploadDialBackground(
            @Parameter(description = "文件", required = true)
            @RequestParam("file") MultipartFile file,
            @Parameter(description = "设备ID", required = true)
            @RequestParam("deviceId") String deviceId,
            HttpServletRequest request) {
        
        try {
            // 验证文件
            if (file.isEmpty()) {
                return RestApiResponse.badRequest("文件不能为空");
            }

            // 验证文件类型
            String contentType = file.getContentType();
            if (contentType == null || !isValidImageType(contentType)) {
                return RestApiResponse.badRequest("只支持上传图片文件（jpg, jpeg, png, gif）");
            }

            // 验证文件大小（20MB）
            if (file.getSize() > 20 * 1024 * 1024) {
                return RestApiResponse.badRequest("文件大小不能超过20MB");
            }

            // 生成唯一的文件名
            String originalFilename = file.getOriginalFilename();
            String fileExtension = "";
            if (originalFilename != null && originalFilename.contains(".")) {
                fileExtension = originalFilename.substring(originalFilename.lastIndexOf("."));
            }
            
            String fileName = UUID.randomUUID().toString() + fileExtension;
            String datePath = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));
            String objectKey = "dial-background/" + datePath + "/" + fileName;

            // 上传到TOS（对象继承桶权限，无需单独设置ACL）
            PutObjectOutput result = tosClientUtils.uploadStream(
                objectKey, 
                file.getInputStream(), 
                file.getSize()
            );

            // 获取TOS直接访问URL
            String directAccessUrl = tosClientUtils.getObjectUrl(objectKey);
            
            // 构建后端代理访问URL（用于表盘背景）
            String scheme = request.getScheme();
            String serverName = request.getServerName();
            int serverPort = request.getServerPort();
            String contextPath = request.getContextPath();
            
            StringBuilder baseUrl = new StringBuilder();
            baseUrl.append("https").append("://").append(serverName);
            if ((scheme.equals("http") && serverPort != 80) || 
                (scheme.equals("https") && serverPort != 443)) {
                baseUrl.append(":").append(serverPort);
            }
            baseUrl.append(contextPath);
            
            String proxyAccessUrl = baseUrl.toString() + "/api/files/view/" + objectKey;
            
            // 更新设备的dial_background_url字段，使用proxyUrl
            deviceService.updateDialBackgroundUrl(deviceId, proxyAccessUrl);

            // 构建响应数据
            Map<String, Object> responseData = new HashMap<>();
            responseData.put("fileName", fileName);
            responseData.put("originalName", originalFilename);
            responseData.put("objectKey", objectKey);
            responseData.put("fileSize", file.getSize());
            responseData.put("contentType", contentType);
            responseData.put("uploadTime", LocalDateTime.now());
            responseData.put("accessUrl", directAccessUrl);
            responseData.put("directUrl", directAccessUrl);
            responseData.put("proxyUrl", proxyAccessUrl);
            responseData.put("deviceId", deviceId);

            log.info("表盘背景图片上传成功: {} -> {} (继承桶权限), 设备URL更新为: {}", objectKey, directAccessUrl, proxyAccessUrl);
            return RestApiResponse.created(responseData);

        } catch (Exception e) {
            log.error("表盘背景图片上传失败", e);
            return RestApiResponse.error("表盘背景图片上传失败: " + e.getMessage());
        }
    }

    /**
     * 验证是否为有效的图片类型
     */
    private boolean isValidImageType(String contentType) {
        return contentType.equals("image/jpeg") ||
               contentType.equals("image/jpg") ||
               contentType.equals("image/png") ||
               contentType.equals("image/gif");
    }

    /**
     * 根据文件扩展名确定内容类型
     */
    private String determineContentType(String objectKey) {
        String lowerKey = objectKey.toLowerCase();
        if (lowerKey.endsWith(".jpg") || lowerKey.endsWith(".jpeg")) {
            return "image/jpeg";
        } else if (lowerKey.endsWith(".png")) {
            return "image/png";
        } else if (lowerKey.endsWith(".gif")) {
            return "image/gif";
        } else if (lowerKey.endsWith(".webp")) {
            return "image/webp";
        } else if (lowerKey.endsWith(".svg")) {
            return "image/svg+xml";
        } else {
            return "application/octet-stream";
        }
    }
}